import hudson.model.*;
import com.fasterxml.jackson.databind.ObjectMapper

pipeline {
    agent any
    // 环境变量
    environment {
        // docker私有仓库凭证
        harbor_docker_credentials = credentials('harbor-docker')

        successInfo = null
        failInfo = null
    }
    // 入参定义
    parameters {
        string(name: 'hospitalList', defaultValue: '', description: '机构列表JSON字符串')
        string(name: 'project_name', defaultValue: 'tz-hospital-ssm-admin', description: '项目名称')
        string(name: 'git_url', defaultValue: 'http://admin@172.16.108.28:8901/r/tz-hospital-ssm-admin.git', description: '仓库地址')
        string(name: 'branch_name', defaultValue: 'test', description: 'git分支')
        string(name: 'registry_url', defaultValue: '193.193.188.91', description: '镜像仓库地址')
        string(name: 'registry_ns', defaultValue: 'ssm-docker-swarm', description: '镜像命名空间')
        string(name: 'pull_image_url', defaultValue: '10.15.3.32:1801', description: '拉取镜像地址')
        string(name: 'service_name', defaultValue: 'service01_webapp', description: '服务名')
        string(name: 'user_email', defaultValue: '125139887@qq.com', description: '邮件通知')
    }
    stages {
        stage('检出代码') {
            steps {
                // 检出代码
                checkout([$class                           : 'GitSCM', branches: [[name: "*/${params.branch_name}"]],
                          doGenerateSubmoduleConfigurations: false,
                          extensions                       : [],
                          submoduleCfg                     : [],
                          userRemoteConfigs                : [[
                                                                      credentialsId: 'gitblit',
                                                                      url          : "${params.git_url}"]]])
            }
        }
        stage("编译打包") {
            steps {
                sh "pwd"
                sh "npm install --registry https://registry.npm.taobao.org"
                sh "npm run build"
            }
        }
        stage('构建镜像及推送到docker仓库&&循环发布到远程') {
            steps {
                script {
                    sh "pwd"
                    //获取发布机构列表
                    def slurped = new groovy.json.JsonSlurperClassic().parseText(params.hospitalList)
                    // 成功列表
                    List successList = new ArrayList();
                    // 错误列表
                    List failList = new ArrayList();

                    for (info in slurped) {
                        // 镜像版本
                        image_tag = sh(returnStdout: true, script: 'echo `date +"%Y%m%d%H%M%S"`').trim()
                        def imgName = "${params.pull_image_url}/${params.registry_ns}/${params.project_name}:${image_tag}"
                        def orgMsg = "=======" + info.orgName + "======" + info.ipAddr + "======"
                        try {
                            // 获取远程IP对象
                            def sshServer = getServer(info.ipAddr, info.sshPort, info.orgCode)
                            // 测试远程是否可连接
                            sshCommand remote: sshServer, command: "date"

                            sh "echo 开始执行" + orgMsg

                            sh "rm -f dist/config.js"
                            sh "rm -f dist/config10.js"
                            sh "rm -f dist/index10.html"

                            // 替换config.js
                            sh "sed -e 's#{{host}}#${info.hospitalLocalhost}#g;s#{{prot}}#5622#g' config.tpl > dist/config.js"
                            // 10地址访问
                            sh "sed -e 's#{{host}}#${info.ipAddr}#g;s#{{prot}}#5622#g' config.tpl > dist/config10.js"
                            sh "sed -e 's#./config.js#./config10.js#g' dist/index.html > dist/index10.html"

                            // 服务器先执行 sudo chmod a+rw /var/run/docker.sock
                            // 登录镜像仓库
                            sh "docker login -u ${harbor_docker_credentials_USR} -p ${harbor_docker_credentials_PSW} ${params.registry_url}"
                            // 构建镜像
                            sh "docker build -t ${params.registry_url}/${params.registry_ns}/${params.project_name}:${image_tag} ."
                            // 推送镜像到私服
                            sh "docker push ${params.registry_url}/${params.registry_ns}/${params.project_name}:${image_tag}"
                            //delete docker images
                            sh "docker rmi ${params.registry_url}/${params.registry_ns}/${params.project_name}:${image_tag}"

                            println("执行开始")
                            sh "echo " + imgName


                            // 更新或下载镜像
                            sshCommand remote: sshServer, command: "docker service update --image=${imgName} ${params.service_name}"
                            successList.add(new IpAddrInfo(orgCode: info.orgCode, orgName: info.orgName, ipAddr: info.ipAddr, msg: "发布成功", hospitalLocalhost: info.hospitalLocalhost, image: imgName))
                            sh "echo 执行成功"
                        } catch (ex) {
                            println(ex)
                            //记录错误信息
                            failList.add(new IpAddrInfo(ipAddr: info.ipAddr, msg: ex.message, image: imgName))
                        }
                    }
                    //记录成功和失败信息到环境变量
                    ObjectMapper successObj = new ObjectMapper()
                    successInfo = successObj.writeValueAsString(successList)
                    ObjectMapper failObj = new ObjectMapper()
                    failInfo = failObj.writeValueAsString(failList)
                }
            }
        }
        stage('执行成功打印') {
            steps {
                script {
                    println(successInfo)
                }
            }
        }
        stage('执行失败打印') {
            steps {
                script {
                    println(failInfo)
                }
            }
        }
    }
    post('发送通知') {
        success {
            emailext(
                    subject: "【SUCCESS】## 项目构建通知 ## $env.JOB_NAME - Build # $env.BUILD_NUMBER",
                    body: """
~
变动日志
========================
${getChangeString()}
========================

发布成功列表
========================
${successInfo}
========================

发布失败列表
========================
${failInfo}
========================
                    """,
                    to: "${params.user_email}"
            )
        }
        failure {
            emailext(
                    subject: "【FAIL】## 项目构建通知 ##$env.JOB_NAME - Build # $env.BUILD_NUMBER",
                    body: """
~
变动日志
========================
${getChangeString()}
========================

发布成功列表
========================
${successInfo}
========================

发布失败列表
========================
${failInfo}
========================
                    """,
                    to: "${params.user_email}"
            )
        }
    }
}

class IpAddrInfo {
    String orgCode
    String orgName
    String ipAddr
    String hospitalLocalhost
    String msg
    String image
}

def getServer(ip, port, orgCode) {
    def remote = [:]
    remote.name = "server-${ip}"
    remote.host = ip
    remote.port = port
    remote.allowAnyHosts = true
    withCredentials([usernamePassword(credentialsId: orgCode, passwordVariable: 'password', usernameVariable: 'userName')]) {
        remote.user = "${userName}"
        remote.password = "${password}"
    }
    return remote
}

@NonCPS
def getChangeString() {
    MAX_MSG_LEN = 100
    def changeString = ""
    def changeLogSets = currentBuild.changeSets
    for (int i = 0; i < changeLogSets.size(); i++) {
        def entries = changeLogSets[i].items
        for (int j = 0; j < entries.length; j++) {
            def entry = entries[j]
            truncated_msg = entry.msg.take(MAX_MSG_LEN)
            changeString += "--${truncated_msg}  [${entry.author}]\n"
        }
    }
    if (!changeString) {
        changeString = " - 无"
    }
    echo changeString
    return changeString
}